/*
** smse2k core
*/

#include <windows.h>
#include "smse2kincludes.h"
#include "smse2k.h"
#include "FileSystem.h"
#include "File.h"
#include "exception.h"
#include "driverincludes.h"

/**********************************
	Static Variables etc.
TODO: move these into contexts
**********************************/
static int channels = 2;						// Channels (default Stereo)
static int sample_rate = 44100;					// Sampling rate the driver is going to run at
static IMediaPlayer* mplayer = NULL;			// Media player interface. This helps out Winamp etc
static int isInDbgMode = 0;


/***********************************
		C++ Stuff
***********************************/

void CSmseContext::SetTrack(UINT32 code) {
	if (driver) driver->SetSubsong(code);
	else Msg("CONTEXT: No driver assigned\n");
}

int CSmseContext::Buffer(short* buf, int length) {
	int bufferframesdone;

	if (!driver || !hardware) {
		Msg("Context is corrupt, cannot buffer\n");
		return 0;
	}
	__try {
		bufferframesdone = hardware->RunAudioFrames(buf, length);
	} __except (  Exception(GetExceptionInformation())  ) {
		;
	}

	return bufferframesdone;

}

void CSmseContext::Stats() {
	Msg("\n");
	Msg("************************************************\n");
	Msg("SMSE2K statistics dump via SMSE_Stats\n");
	Msg("************************************************\n");
	Msg("SMSE2K Build: " __DATE__ " " __TIME__ "\n");
	Msg("Context located at 0x%08X\n", this);
	OutputDriverList();
	OutputCPUList();

	Msg("*** End of internal context dump\n");
}

int CSmseContext::BootDriver(const char* name) {

	this->driver = DriverFactory(name);
	if (!driver) {
		Msg("Driver not known, stopping\n");
		return 1;
	}

	if (driver->Load(NULL)) {
		Msg("File load error in the driver, dying\n");
		delete[] driver;
		driver = NULL;
		return 1;
	}

	this->hardware = new CHardware(44100);
	if (driver->Init(hardware)) {
		Msg("Hardware init failed\n");
		driver->Close();
		hardware->Shutdown();
		if (driver) delete[] driver;
		if (hardware) delete[] hardware;
		return 1;
	}
	return 0;
}

int CSmseContext::LoadFile(char *fn) {
	char* extension = strrchr(fn,'.') + 1;

	// check to make sure the file exists
	FILE_HANDLE f = filesystem.OpenFile(fn,FSYS_PERMISSION_READ);
	if (!f) {
		Msg("File does not exist or cannot be opened for reading!\n");
		return 1;
	}

	filesystem.CloseFile(f);
	
	Msg("Filetype: %s\n",extension);

	if (!strcmpi(extension,"lua")) {
		Msg("Extension is Lua, booting into Lua environment.\n");

		Msg("unimplemented\n");
		return 1;
	}

	Msg("Looking for suitable driver...");

	this->driver = DriverFactory_CreateDriverByExtension(extension);
	if (!this->driver) {
			Msg("No driver supports the filetype extension %s, stopping load\n", extension);
			return 1;
	}

	Msg("ok\nLoading file...\n");

	if (driver->Load(fn)) {
		Msg("File load failed, check log\n");
		driver->Close();
		delete[] driver;
		return 1;
	}

	// Create hardware and send it to driver init
	Msg("Creating hardware...\n");

	hardware = new CHardware(44100);

	if (driver->Init(hardware)) {
		Msg("Failed to initialize hardware\n");
		driver->Close();
		hardware->Shutdown();
		if (driver) delete[] driver;
		if (hardware) delete[] hardware;
		return 1;

	}


	return 0; // Unimplemented
}

void CSmseContext::Close() {
	driver->Close();
	hardware->Shutdown();

	delete[] driver;
	delete[] hardware;
}

void CSmseContext::SetOutput(int sr, int ch) {
	hardware->SetOutput(sr);
}


/***********************************
		      C Exports
***********************************/

int SMSE_IsInDebugMode() {
#ifdef __DEBUG
	return 1;
#else
	return isInDbgMode;
#endif
}

void SMSE_Stats() {
	Msg("\n");
	Msg("************************************************\n");
	Msg("SMSE2K statistics dump via SMSE_Stats\n");
	Msg("************************************************\n");
	Msg("SMSE2K build: " __DATE__ " " __TIME__ "\n");
	Msg("Host environment: Not known\n");
	OutputDriverList();
	OutputCPUList();
	OutputSNDList();
	Msg("*** End of internal dump\n");
}

HSmseTag SMSE_LoadTags(char* fn) {
	return NULL;
}

int SMSE_SaveTags(char* fn) {
	return 1;
}

char* SMSE_GetTagValue(HSmseTag tag, char* tagfield) {
	return NULL;
}

void SMSE_SetTagValue(HSmseTag tag, char* tagfield, char* value) {
	
}

// One time initialization function
void SMSE_SetOutput(HSmseContext context, int sr, int ch) {
	context->SetOutput(sr,ch);
}

void SMSE_Close(HSmseContext context) {
	
	context->Close();
	delete context;

}

CSmseContext* SMSE_NewContext() {
	return new CSmseContext;
}

int SMSE_LoadFile(HSmseContext context, char* fn) {
	int return_value;
	__try {
		return_value = context->LoadFile(fn);
	} __except( Exception(GetExceptionInformation()) ) {
		
		

	}

	return return_value;
}


int SMSE_BootDriver(HSmseContext ctx, char* name) {
	__try {
		return ctx->BootDriver(name);//bufferframesdone = hardware->RunAudioFrames(buf, length);
	} __except (  Exception(GetExceptionInformation())  ) {
		return NULL;
	}
}

void SMSE_SetTrack(HSmseContext context, UINT32 code) {
	context->SetTrack(code);

}

int SMSE_Buffer(HSmseContext context, short* buf, int length) {
	return context->Buffer(buf,length);
}

// Entry point for smsesvc32 / smsesvc64
void ServiceEntryPoint() {

	Msg("smse2k entered service mode. Waiting for remote connection...\n");
	
	// trap
	while (1);
}